/*
 * graph2D
 * Copyright (c) 2009 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif

#define USE_TEXT_WINDOW

#include "identification.h"
#include "common.h"
#include "desktop.h"
#include "audioPlayer.h"
#include "soundPlayer.h"
#include "dialog.h"
#include "graphicDevice.h"
#include "profile.h"
#if defined(USE_TEXT_WINDOW)
#include "textWindow.h"
#else
#include "messageWindow.h"
#endif
#include "textureContainer.h"
#include <ctime>
#include <stdlib.h>
#include <vector>

#define DEBUG_FONT_TEXTURE_WIDTH 128
#define DEBUG_FONT_WIDTH 8
#define DEBUG_FONT_HEIGHT 8

namespace Graph2D
{
	Desktop* Desktop::instance = NULL;

	static void fade(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 5);

		const float r = mana_actor_get_parameter_float(actor, 0);
		const float g = mana_actor_get_parameter_float(actor, 1);
		const float b = mana_actor_get_parameter_float(actor, 2);
		const float a = mana_actor_get_parameter_float(actor, 3);
		const float second = mana_actor_get_parameter_float(actor, 4);

		Desktop::getInstance().setFadeColor(Color(r, g, b, a), second);
	}

	static void loadImage(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		char* filename = mana_actor_get_parameter_string(actor, 0);

		Scene& scene = Desktop::getInstance().getScene();
		if(!scene.loadTexture(filename))
		{
			abort(ERROR_CODE_FILE_NOT_FOUND, filename);
		}
	}

	// native int create(float x, float y, float w, float h);
	static void create(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 4);

		VariableContainer* container = new VariableContainer();
		if(container)
		{
			float x = mana_actor_get_parameter_float(actor, 0);
			float y = mana_actor_get_parameter_float(actor, 1);
			float w = mana_actor_get_parameter_float(actor, 2);
			float h = mana_actor_get_parameter_float(actor, 3);

			container->setPosition(x, y);
			container->setSize(w, h);
			mana_actor_set_return_integer(actor, static_cast<int>(container->getID()));
		}
		else
		{
			mana_actor_set_return_integer(actor, ~0);
		}
	}

	// native void destroy(int id);
	static void destroy(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);
#if 0
		Component* component = Component::find(identification);
		if(component)
			component->release();
#endif
	}

	// native void touchable(int id, int enable);
	static void touchable(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 2);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
			component->setTouchable(mana_actor_get_parameter_integer(actor, 1) ? true : false);
	}

	// native void changeScene(int type);
	static void changeScene(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);
#if 0
		if(mana_actor_is_init(actor))
		{
			const int sceneType = mana_actor_get_parameter_integer(actor, 0);
			Scene* scene = new Scene(sceneType);
			if(scene)
			{
				Desktop::getInstance().setScene(scene);
				scene->release();
				mana_actor_repeat(actor, MANA_TRUE);
			}
			else
			{
				abort(ERROR_CODE_ILLEGAL_SCENE_OBJECT_DETECTED);
			}
		}
#endif
	}

	// native void swapScene();
	static void swapScene(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 0);
		Desktop::getInstance().swapScene(false);
	}

	// native int getScene();
	static void getScene(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 0);
		mana_actor_set_return_integer(actor, Desktop::getInstance().getScene().getID());
	}

	// native void setLayer(int parent, int layer, int id);
	static void setLayer(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		const unsigned int parent = (unsigned int)mana_actor_get_parameter_integer(actor, 0);
		const unsigned int layer = (unsigned int)mana_actor_get_parameter_integer(actor, 1);
		const unsigned int child = (unsigned int)mana_actor_get_parameter_integer(actor, 2);

		Container* parentContainer = reinterpret_cast<Container*>(Component::find(parent));
		if(parentContainer && parentContainer->isKindOfA(TYPE_CONTAINER))
		{
			Component* childComponent = Component::find(child);
			if(childComponent)
			{
				parentContainer->set(layer, childComponent);
			}
		}
	}

	// native void swapLayer(int parent, int to, int from);
	static void swapLayer(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		const unsigned int parent = (unsigned int)mana_actor_get_parameter_integer(actor, 0);
		const unsigned int to = (unsigned int)mana_actor_get_parameter_integer(actor, 1);
		const unsigned int from = (unsigned int)mana_actor_get_parameter_integer(actor, 2);

		Container* parentContainer = reinterpret_cast<Container*>(Component::find(parent));
		if(parentContainer && parentContainer->isKindOfA(TYPE_CONTAINER))
		{
			Component* fromComponent = parentContainer->get(from);
			Component* toComponent = parentContainer->get(to);
			parentContainer->set(to, fromComponent);
			parentContainer->set(from, toComponent);
		}
	}

	// native void releaseLayer(int parent, int layer);
	static void releaseLayer(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 2);

		const unsigned int parent = (unsigned int)mana_actor_get_parameter_integer(actor, 0);
		const unsigned int layer = (unsigned int)mana_actor_get_parameter_integer(actor, 1);

		Container* parentContainer = reinterpret_cast<Container*>(Component::find(parent));
		if(parentContainer && parentContainer->isKindOfA(TYPE_CONTAINER))
		{
			parentContainer->set(layer, NULL);
		}
	}

	// native void setPosition(int id, float x, float y);
	static void setPosition(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const float x = mana_actor_get_parameter_float(actor, 1);
			const float y = mana_actor_get_parameter_float(actor, 2);
			component->setPosition(x, y);
		}
	}

	// native void setSize(int id, float w, float h);
	static void setSize(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const float x = mana_actor_get_parameter_float(actor, 1);
			const float y = mana_actor_get_parameter_float(actor, 2);
			component->setSize(x, y);
		}
	}

	// native void setScale(int id, float x, float y, float second);
	static void setScale(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 4);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const float x = mana_actor_get_parameter_float(actor, 1);
			const float y = mana_actor_get_parameter_float(actor, 2);
			const float t = mana_actor_get_parameter_float(actor, 3);
			component->setScale(Vector2(x, y), t);
		}
	}

	// native void setColor(int id, float r, float g, float b, float a, float second);
	static void setColor(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 6);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const float r = mana_actor_get_parameter_float(actor, 1);
			const float g = mana_actor_get_parameter_float(actor, 2);
			const float b = mana_actor_get_parameter_float(actor, 3);
			const float a = mana_actor_get_parameter_float(actor, 4);
			const float second = mana_actor_get_parameter_float(actor, 5);

			component->setColor(Color(r, g, b, a), second);
		}
	}

	// native void loadTexture(int id, string filename);
	static void loadTexture(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 2);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const char* filename = mana_actor_get_parameter_string(actor, 1);
			if(!component->loadTexture(filename))
				abort(ERROR_CODE_FILE_OPEN_FAILED, filename);
		}
	}

	// native void setTextureScroll(int id, float x, float y);
	static void setTextureScroll(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const float x = mana_actor_get_parameter_float(actor, 1);
			const float y = mana_actor_get_parameter_float(actor, 2);
			// TODO
			//component->setTextureScroll(Vector2(x, y));
		}
	}

	// native void loadScript(int id, string filename)
	static void loadScript(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 2);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);
		Component* component = Component::find(identification);
		if(component)
		{
		/*
			const char* filename = mana_actor_get_parameter_string(actor, 1);
			if(!component->loadScript(filename))
				abort(ERROR_CODE_FILE_OPEN_FAILED, filename);
				*/
		}
	}

	// native void setCellAnimation(float width, float height, float wait, int start, int count, int loopCount);
	static void setCellAnimation(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 8);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			float x = mana_actor_get_parameter_float(actor, 1);
			float y = mana_actor_get_parameter_float(actor, 2);
			float w = mana_actor_get_parameter_float(actor, 3);
			float h = mana_actor_get_parameter_float(actor, 4);
			const float t = mana_actor_get_parameter_float(actor, 5);
			const short l = static_cast<short>(mana_actor_get_parameter_integer(actor, 6));
			const short c = static_cast<short>(mana_actor_get_parameter_integer(actor, 7));

			const Texture* texture = component->getTexture();
			if(texture)
			{
				const Vector2& textureSize = texture->getSize();

				Animation* animation = static_cast<Animation*>(alloca(sizeof(Animation) * l));
				for(size_t i = 0; i < l; ++i)
				{
					Animation& a = animation[i];
					a.wait = t;
					a.uv.set(x, y);
					a.wh.set(w, h);

					x += w;
					if(x + w > textureSize.x)
					{
						x = 0;
						y += h;
						if(y + h > textureSize.y)
							y = 0;
					}
				}
				component->setAnimation(l, animation, c != 0);
			}
		}
	}

	// native void startCellAnimation();
	static void startCellAnimation(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

#if 0
		// TODO
		Component* component = Component::find(identification);
		if(component)
			component->startCellAnimation();
#endif
	}

	// native void stopCellAnimation();
	static void stopCellAnimation(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

#if 0
		// TODO
		Component* component = Component::find(identification);
		if(component)
			component->stopCellAnimation();
#endif
	}

	// native void setCellNumber(int id, int pattern);
	static void setCellNumber(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 2);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

#if 0
		// TODO
		Component* component = Component::find(identification);
		if(component)
		{
			const int pattern = mana_actor_get_parameter_integer(actor, 1);
			component->setCellNumber(pattern);
		}
#endif
	}

	// native void addAnimation(int id, string name, float x, float y, float w, float h, float wait, int count, int loop);
	static void addAnimation(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 8);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
#if 0
			// TODO
			const char* name = mana_actor_get_parameter_string(actor, 1);
			const float x = mana_actor_get_parameter_float(actor, 2);
			const float y = mana_actor_get_parameter_float(actor, 3);
			const float w = mana_actor_get_parameter_float(actor, 4);
			const float h = mana_actor_get_parameter_float(actor, 5);
			const short c = static_cast<short>(mana_actor_get_parameter_integer(actor, 6));
			const short l = static_cast<short>(mana_actor_get_parameter_integer(actor, 7));
			CellAnimation* cellAnimation = new CellAnimation(Vector2(x, y), Vector2(w, h), w, c, l);
			component->addAnimation(name, cellAnimation);
			cellAnimation->release();
#endif
		}
	}

	// native void removeAnimation(int id, string name);
	static void removeAnimation(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 2);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

#if 0
		// TODO
		Component* component = Component::find(identification);
		if(component)
		{
			const char* name = mana_actor_get_parameter_string(actor, 1);
			component->removeAnimation(name);
		}
#endif
	}

	// native void setAnimation(int id, string name);
	static void setAnimation(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 2);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

#if 0
		// TODO
		Component* component = Component::find(identification);
		if(component)
		{
			char* name = mana_actor_get_parameter_string(actor, 1);
			component->setAnimation(name);
		}
#endif
	}

	// native void waitAnimation(int id);
	static void waitAnimation(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

#if 0
		// TODO
		Component* component = Component::find(identification);
		if(component && component->isRunningCellAnimation())
		{
			mana_actor_repeat(actor, MANA_TRUE);
		}
#endif
	}

	// native void move(int id, float x, float y, float time);
	static void move(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 4);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const float x = mana_actor_get_parameter_float(actor, 1);
			const float y = mana_actor_get_parameter_float(actor, 2);
			const float t = mana_actor_get_parameter_float(actor, 3);

			component->move(Vector2(x, y), t);
		}
	}

	// native void moveFinish(int id);
	static void moveFinish(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component && component->arrived() == false)
			mana_actor_repeat(actor, MANA_TRUE);
	}

	// native void jump(int id, float time, float height);
	static void jump(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const float height = mana_actor_get_parameter_float(actor, 1);
			const float time = mana_actor_get_parameter_float(actor, 2);
			component->jump(height, time);
		}
	}

	// native void shake(int id, float time, float amplitude);
	static void shake(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		const unsigned int identification = (unsigned int)mana_actor_get_parameter_integer(actor, 0);

		Component* component = Component::find(identification);
		if(component)
		{
			const float time = mana_actor_get_parameter_float(actor, 1);
			const float amplitude = mana_actor_get_parameter_float(actor, 2);
			component->shake(amplitude, time);
		}
	}

	// native void openMessageWindow();
	static void openMessageWindow(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 0);
/*
		Graph2D::Scene& currentScene = Desktop::getInstance().getScene();
#if defined(USE_TEXT_WINDOW)
		Graph2D::Window* window = static_cast<Graph2D::Window*>(currentScene.getTextWindow());
#else
		Graph2D::Window* window = static_cast<Graph2D::Window*>(currentScene.getMessageWindow());
#endif
		if(window)
		{
			window->open();
		}
		*/
	}

	//native void closeMessageWindow();
	static void closeMessageWindow(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 0);
/*
		Graph2D::Scene& currentScene = Desktop::getInstance().getScene();
#if defined(USE_TEXT_WINDOW)
		Graph2D::Window* window = static_cast<Graph2D::Window*>(currentScene.getTextWindow());
#else
		Graph2D::Window* window = static_cast<Graph2D::Window*>(currentScene.getMessageWindow());
#endif
		if(window)
		{
			window->close();
		}
		*/
	}

	static void showMessage(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		Graph2D::Scene& currentScene = Desktop::getInstance().getScene();
#if defined(USE_TEXT_WINDOW)
		Graph2D::TextWindow* window = static_cast<Graph2D::TextWindow*>(currentScene.getTextWindow());
		if(window)
		{
			if(mana_actor_is_init(actor))
			{
				window->setString(mana_actor_get_parameter_string(actor, 0));
				window->setVisible(true);
			}
			if(!window->finished())
			{
				mana_actor_repeat(actor, MANA_TRUE);
			}
			else
			{
				window->clear();
			}
		}
#else
		Graph2D::MessageWindow* window = static_cast<Graph2D::MessageWindow*>(currentScene.getMessageWindow());
		if(window)
		{
			if(mana_actor_is_init(actor))
			{
				window->setString(mana_actor_get_parameter_string(actor, 0));
				window->setVisible(true);
			}
			if(!window->finished())
			{
				mana_actor_repeat(actor, MANA_TRUE);
			}
			else
			{
				window->clear();
			}
		}
#endif
	}

	static void setMessage(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		Graph2D::Scene& currentScene = Desktop::getInstance().getScene();
#if defined(USE_TEXT_WINDOW)
		Graph2D::TextWindow* window = static_cast<Graph2D::TextWindow*>(currentScene.getTextWindow());
		if(window)
		{
			window->setString(mana_actor_get_parameter_string(actor, 0));
			window->setVisible(true);
		}
#else
		Graph2D::MessageWindow* window = static_cast<Graph2D::MessageWindow*>(currentScene.getMessageWindow());
		if(window)
		{
			window->setString(mana_actor_get_parameter_string(actor, 0));
			window->setVisible(true);
		}
#endif
	}

	// native void waitMessage();
	static void waitMessage(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 0);

		Graph2D::Scene& currentScene = Desktop::getInstance().getScene();

#if defined(USE_TEXT_WINDOW)
		Graph2D::TextWindow* window = static_cast<Graph2D::TextWindow*>(currentScene.getTextWindow());
#else
		Graph2D::MessageWindow* window = static_cast<Graph2D::MessageWindow*>(currentScene.getMessageWindow());
#endif
		if(!window->finished())
		{
			mana_actor_repeat(actor, MANA_TRUE);
		}
		else
		{
			window->clear();
		}
	}

	//native void setMessageColor(float r, float g, float b, float a);
	static void setMessageColor(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 4);

		Graph2D::Scene& currentScene = Desktop::getInstance().getScene();
#if defined(USE_TEXT_WINDOW)
		Graph2D::TextWindow* window = static_cast<Graph2D::TextWindow*>(currentScene.getTextWindow());
		if(window)
		{
			const float r = mana_actor_get_parameter_float(actor, 0);
			const float g = mana_actor_get_parameter_float(actor, 1);
			const float b = mana_actor_get_parameter_float(actor, 2);
			const float a = mana_actor_get_parameter_float(actor, 3);
			window->setTextColor(r, g, b, a);
		}
#else
		Graph2D::MessageWindow* window = static_cast<Graph2D::MessageWindow*>(currentScene.getMessageWindow());
		if(window)
		{
			const float r = mana_actor_get_parameter_float(actor, 0);
			const float g = mana_actor_get_parameter_float(actor, 1);
			const float b = mana_actor_get_parameter_float(actor, 2);
			const float a = mana_actor_get_parameter_float(actor, 3);
			window->setTextColor(r, g, b, a);
		}
#endif
	}

	//native void setMessageDelayTimer(float delayTimer);
	static void setMessageDelayTimer(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		Graph2D::Scene& currentScene = Desktop::getInstance().getScene();
#if defined(USE_TEXT_WINDOW)
		Graph2D::TextWindow* window = static_cast<Graph2D::TextWindow*>(currentScene.getTextWindow());
		if(window)
		{
			window->setAutoCloseTimer(mana_actor_get_parameter_float(actor, 0));
		}
#else
		Graph2D::MessageWindow* window = static_cast<Graph2D::MessageWindow*>(currentScene.getMessageWindow());
		if(window)
		{
			window->setDelayTimer(mana_actor_get_parameter_float(actor, 0));
		}
#endif
	}

	static void getMessageWindow(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 0);

		Graph2D::Scene& currentScene = Desktop::getInstance().getScene();

#if defined(USE_TEXT_WINDOW)
		Graph2D::TextWindow* window = static_cast<Graph2D::TextWindow*>(currentScene.getTextWindow());
#else
		Graph2D::MessageWindow* window = static_cast<Graph2D::MessageWindow*>(currentScene.getMessageWindow());
#endif
		const unsigned int identification = window ? window->getID() : ~0;

		mana_actor_set_return_integer(actor, identification);
	}

	static void _select(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);
#if 0
		// TODO:選択系のコマンドがあるとなにかと便利！
		Dialog& dialog = Desktop::getInstance().getScene().getDialog();

		if(mana_actor_is_init(actor))
		{
			dialog.initialize(mana_actor_get_parameter_string(actor, 0));
			dialog.open();
		}

		const int answer = dialog.result();
		if(answer >= 0)
		{
			mana_actor_set_return_integer(actor, answer);

			dialog.close();
		}
		else
		{
			mana_actor_repeat(actor, MANA_TRUE);
		}
#endif
	}

	// native int touch();
	static void touch(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 0);

		if(mana_actor_is_init(actor))
		{
			Component::clearLastTouchedComponentID();
		}

		const unsigned int lastTouchedComponentID = Component::getLastTouchedComponentID();
		if(lastTouchedComponentID != 0)
			mana_actor_set_return_integer(actor, lastTouchedComponentID);
		else
			mana_actor_repeat(actor, MANA_TRUE);
	}

	//native int checkTouch(int initial);
	static void checkTouch(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		if(mana_actor_get_parameter_integer(actor, 0))
		{
			Component::clearLastTouchedComponentID();
		}

		const unsigned int lastTouchedComponentID = Component::getLastTouchedComponentID();
		mana_actor_set_return_integer(actor, lastTouchedComponentID);
	}

	//native int talk(string filename);
	static void talk(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		char* filename = mana_actor_get_parameter_string(actor, 0);
		mana_actor_set_return_integer(actor, AudioPlayer::getInstance().talk(filename));
	}

	//native int playMusic(string filename, float volume, float time);
	static void playMusic(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		char* n = mana_actor_get_parameter_string(actor, 0);
		const float v = mana_actor_get_parameter_float(actor, 1);
		const float t = mana_actor_get_parameter_float(actor, 2);
		mana_actor_set_return_integer(actor, AudioPlayer::getInstance().play(n, v, t));
	}

	//native void stopMusic(int id, float volume, float time);
	static void stopMusic(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 2);

		const int i = mana_actor_get_parameter_integer(actor, 0);
		const float t = mana_actor_get_parameter_float(actor, 1);
		AudioPlayer::getInstance().stop(i, t);
	}

	//native void setMusicVolume(int id, float volume, float time);
	static void setMusicVolume(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 3);

		const int i = mana_actor_get_parameter_integer(actor, 0);
		const float v = mana_actor_get_parameter_float(actor, 1);
		const float t = mana_actor_get_parameter_float(actor, 2);
		AudioPlayer::getInstance().volume(i, v, t);
	}

	//native int loadSound(string filename);
	static void loadSound(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		int identification = -1;
		Sound::DataManager* dataManager = Desktop::getInstance().getSoundDataManager(SOUND_PLAYER_ID_SE);
		if(dataManager)
		{
			const char* filename = mana_actor_get_parameter_string(actor, 0);
			identification = dataManager->load(filename);
		}
		mana_actor_set_return_integer(actor, identification);
	}

	//native void releaseSound(int id);
	static void releaseSound(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		Sound::DataManager* dataManager = Desktop::getInstance().getSoundDataManager(SOUND_PLAYER_ID_SE);
		if(dataManager)
		{
			const size_t identification = (size_t)mana_actor_get_parameter_integer(actor, 0);
			dataManager->release(identification);
		}
	}

	//native void playSound(int id);
	static void playSound(mana_actor* actor)
	{
		MANA_ASSERT_PARAMETER(actor, 1);

		Sound::Player* player = Desktop::getInstance().getSoundPlayer();
		if(player)
		{
			const size_t identification = (size_t)mana_actor_get_parameter_integer(actor, 0);
			player->play(identification);
		}
	}

	////////////////////////////////////////////////////////////////////////////////
	Desktop::Desktop()
		: userControl(true)
		, releaseBackScene(false)
		, player(NULL)
		, musicPlayer(NULL)
	{
		// ランダム初期化
		srand(static_cast<unsigned int>(time(NULL)));

		// スクリプトシステムの初期化
		mana_initialize();

		MANA_REGIST_FUNCTION(fade);
		MANA_REGIST_FUNCTION(loadImage);

		MANA_REGIST_FUNCTION(create);
		MANA_REGIST_FUNCTION(destroy);
		MANA_REGIST_FUNCTION(touchable);

		mana_regist_function((char*)"changeScene", Graph2D::changeScene);
		mana_regist_function((char*)"swapScene", Graph2D::swapScene);
		mana_regist_function((char*)"getScene", Graph2D::getScene);

		MANA_REGIST_FUNCTION(setLayer);
		MANA_REGIST_FUNCTION(swapLayer);
		MANA_REGIST_FUNCTION(releaseLayer);

		MANA_REGIST_FUNCTION(setPosition);
		mana_regist_function((char*)"setSize", Graph2D::setSize);
		MANA_REGIST_FUNCTION(setScale);
		MANA_REGIST_FUNCTION(setColor);

		MANA_REGIST_FUNCTION(loadTexture);
		MANA_REGIST_FUNCTION(setTextureScroll);

		mana_regist_function((char*)"loadScript", Graph2D::loadScript);

		MANA_REGIST_FUNCTION(setCellAnimation);
		MANA_REGIST_FUNCTION(startCellAnimation);
		MANA_REGIST_FUNCTION(stopCellAnimation);
		MANA_REGIST_FUNCTION(setCellNumber);

		MANA_REGIST_FUNCTION(addAnimation);
		MANA_REGIST_FUNCTION(removeAnimation);
		MANA_REGIST_FUNCTION(setAnimation);
		MANA_REGIST_FUNCTION(waitAnimation);

		MANA_REGIST_FUNCTION(move);
		MANA_REGIST_FUNCTION(moveFinish);
		MANA_REGIST_FUNCTION(jump);
		MANA_REGIST_FUNCTION(shake);

		MANA_REGIST_FUNCTION(openMessageWindow);
		MANA_REGIST_FUNCTION(closeMessageWindow);
		MANA_REGIST_FUNCTION(showMessage);
		MANA_REGIST_FUNCTION(setMessage);
		MANA_REGIST_FUNCTION(waitMessage);
		MANA_REGIST_FUNCTION(setMessageColor);
		MANA_REGIST_FUNCTION(setMessageDelayTimer);
		MANA_REGIST_FUNCTION(getMessageWindow);

		mana_regist_function((char*)"select", _select);
		MANA_REGIST_FUNCTION(touch);
		MANA_REGIST_FUNCTION(checkTouch);

		MANA_REGIST_FUNCTION(talk);
		MANA_REGIST_FUNCTION(playMusic);
		MANA_REGIST_FUNCTION(stopMusic);
		MANA_REGIST_FUNCTION(setMusicVolume);

		MANA_REGIST_FUNCTION(loadSound);
		MANA_REGIST_FUNCTION(releaseSound);
		MANA_REGIST_FUNCTION(playSound);

		// 画面フェードの初期化
		fadeColor.set(0.0f, 0.0f, 0.0f, 0.0f);
		fadeDeltaColor.set(0.0f, 0.0f, 0.0f, 0.0f);
		fadeTargetColor.set(0.0f, 0.0f, 0.0f, 0.0f);
		fadeColorTime = 0.0f;
		fadeColorEnable = false;

		// サウンドシステムの初期化
		memset(dataManager, 0, sizeof(dataManager));

		// シーンの初期化
		scene = NULL;
		reserveScene = NULL;
		prepareScene = NULL;
		backScene = NULL;

		setScene(&defaultScene);
		changeScene();

#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
		debugMessageInfomation = NULL;
		debugMessageFontTexture = NULL;
#endif
	}

	void Desktop::initializeResources()
	{
#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
		debugMessageFontTexture = TextureContainer::getInstance().load("debug_font.pvr");
#endif
	}

	Desktop::~Desktop()
	{
		// シーンの開放
#if 0
		if(scene)
			scene->release();
		if(reserveScene)
			reserveScene->release();
		if(prepareScene)
			prepareScene->release();
		if(backScene)
			backScene->release();
#endif

		// スクリプトシステムの終了
		mana_finalize();

#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
		// コンポーネントの開放チェック
		Component::dumpAll();
#endif

		// コンポーネントの開放
		Component::clearAll();

#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
		cleanDebugMessage();

		if(debugMessageFontTexture)
		{
			TextureContainer::getInstance().unload(debugMessageFontTexture);
			debugMessageFontTexture = NULL;
		}
#endif
	}

	void Desktop::changeScene()
	{
		if(!requestDeserializeFileName.empty())
		{
			Graph2D::Data data(requestDeserializeFileName, true);
			if(data.valid())
			{
				mana_stream* stream = mana_stream_create();
				mana_stream_push_data(stream, const_cast<void*>(data.getBuffer()), data.getSize());
				mana_stream_rewind(stream);

				if(scene)
				{
					//scene->release();
					scene = NULL;
				}
				if(reserveScene)
				{
					//reserveScene->release();
					reserveScene = NULL;
				}
				if(prepareScene)
				{
					//prepareScene->release();
					prepareScene = NULL;
				}
				if(backScene)
				{
					//backScene->release();
					backScene = NULL;
				}
#if 1
				Component::dumpAll();
#endif
				Identification::clear();

				Graph2D::Component* component = deserialize(stream);
				setScene((Graph2D::Scene*)(component));
				//component->release();

				mana_stream_destroy(stream);

#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
#endif
			}

			requestDeserializeFileName.clear();
		}

		while(reserveScene)
		{
			if(scene)
			{
				//scene->release();
			}

			scene = reserveScene;

			if(prepareScene && prepareScene != scene)
			{
				prepareScene = NULL;
			}

			reserveScene = NULL;

			if(scene)
			{
				while(! scene->onPrepare())
					;

				scene->onInitialize();
			}
		}

		if(releaseBackScene)
		{
			delete backScene;
			backScene = NULL;

			releaseBackScene = false;
		}
	}

	void Desktop::setFadeColor(const Color& color, const float second)
	{
		if(second <= 0)
		{
			fadeColor = color;
		}
		else
		{
			fadeTargetColor = color;
			fadeDeltaColor = (color - fadeColor) * (1.0f / second);
			fadeColorTime = second;
			fadeColorEnable = true;
		}
	}

	void Desktop::serialize(mana_stream* stream) const
	{
		//Message::serializeDefaultSetting(stream);
		if(scene)
			scene->onSerialize(stream);
	}

	Component* Desktop::deserialize(mana_stream* stream) const
	{
		//Message::deserializeDefaultSetting(stream);
		return Component::deserialize(stream);
	}

	void Desktop::touchesBegan(const Vector2& position)
	{
		if(userControl)
		{
			Component* capturedComponent = Component::getMouseCapture();
			if(capturedComponent == NULL)
				capturedComponent = scene;

			if(capturedComponent)
			{
				const Vector2 screenPosition = GraphicDevice::translateScreenPosition(position);
				const Vector2 localPosition = capturedComponent->translatePosition(screenPosition);
				capturedComponent->touchesBegan(localPosition);
			}
		}
	}

	void Desktop::touchesMoved(const Vector2& position)
	{
		if(userControl)
		{
			Component* capturedComponent = Component::getMouseCapture();
			if(capturedComponent == NULL)
				capturedComponent = scene;

			if(capturedComponent)
			{
				const Vector2 screenPosition = GraphicDevice::translateScreenPosition(position);
				const Vector2 localPosition = capturedComponent->translatePosition(screenPosition);
				capturedComponent->touchesMoved(localPosition);
			}
		}
	}

	void Desktop::touchesEnded(const Vector2& position)
	{
		if(userControl)
		{
			Component* capturedComponent = Component::getMouseCapture();
			if(capturedComponent == NULL)
				capturedComponent = scene;

			if(capturedComponent)
			{
				const Vector2 screenPosition = GraphicDevice::translateScreenPosition(position);
				const Vector2 localPosition = capturedComponent->translatePosition(screenPosition);
				capturedComponent->touchesEnded(localPosition);
			}
		}
	}

	void Desktop::touchesCancelled(const Vector2& position)
	{
		if(userControl)
		{
			Component* capturedComponent = Component::getMouseCapture();
			if(capturedComponent == NULL)
				capturedComponent = scene;

			if(capturedComponent)
			{
				const Vector2 screenPosition = GraphicDevice::translateScreenPosition(position);
				const Vector2 localPosition = capturedComponent->translatePosition(screenPosition);
				capturedComponent->touchesCancelled(localPosition);
			}
		}
	}

	void Desktop::updateAndDraw(const float elapsedSeconds)
	{
#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
		Stopwatch updateTime;
#endif
		float second = elapsedSeconds;
		if(second > getMostDelayTime())
			second = getMostDelayTime();
		const float stepCount = second / (1.0f / 30.0f);

		UpdateInfomation updateInfomation;
		updateInfomation.deltaTime = second;
		updateInfomation.stepCount = stepCount;

		PROFILE_SYNC();

		AudioPlayer::getInstance().onUpdate(updateInfomation.deltaTime);
		Sound::update(updateInfomation.deltaTime);

		changeScene();

		PROFILE_BEGIN(Profile::UPDATE);
		if(scene)
		{
			scene->onUpdate(updateInfomation);
		}
		PROFILE_END(Profile::UPDATE);

		if(fadeColorEnable)
		{
			fadeColor += fadeDeltaColor* updateInfomation.deltaTime;

			fadeColorTime -= updateInfomation.deltaTime;
			if(fadeColorTime <= 0)
			{
				fadeColor = fadeTargetColor;
				fadeColorEnable = false;
			}
		}

#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
		const float totalUpdateTime = updateTime.stop();
		print(12, 320-(DEBUG_FONT_HEIGHT*3), "CPU:%1.5f", totalUpdateTime);
		Stopwatch drawTime;
#endif

		GraphicDevice::setScissor(Vector2(0, 0), GraphicDevice::getScreenSize());
		GraphicDevice::enableScissor(true);
		GraphicDevice::clear();

		PROFILE_BEGIN(Profile::DRAW);
		if(scene)
		{
			const DrawRect drawRect;
			scene->onDraw(drawRect);
		}
		PROFILE_END(Profile::DRAW);

		if(fadeColor.a > 0.0f)
		{
			GraphicDevice::begin(0, GraphicDevice::TRIANGLES, fadeColor);
			GraphicDevice::addVertex(Vector2(0.0f, 0.0f));
			GraphicDevice::addVertex(Vector2(GraphicDevice::getScreenWidth(), 0.0f));
			GraphicDevice::addVertex(Vector2(0.0f, GraphicDevice::getScreenHeight()));
			GraphicDevice::addVertex(Vector2(GraphicDevice::getScreenWidth(), 0.0f));
			GraphicDevice::addVertex(Vector2(0.0f, GraphicDevice::getScreenHeight()));
			GraphicDevice::addVertex(GraphicDevice::getScreenSize());
			GraphicDevice::end();
		}

		PROFILE_BEGIN(Profile::SYNC);
		GraphicDevice::flush();
		PROFILE_END(Profile::SYNC);

#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
#if 0
		for(int i = 0; i < Profile::SIZE_OF_CATEGORIES; i++)
		{
			static const char* profileNames[] = {
				"UPDATE",
				"PHASE1",
				"PHASE2",
				"PHASE3",
				"PHASE4",
				"PHASE5",
				"DRAW",
				"SYNC",
			};
			print(12, 320-(DEBUG_FONT_HEIGHT*(4 + Profile::SIZE_OF_CATEGORIES - i)), "%6s:%1.5f",
				  profileNames[i],
				  PROFILE_TICK(static_cast<Profile::Category>(i))
			);
		}
#endif
		const float totalDrawtime = drawTime.stop();
		print(12, 320-(DEBUG_FONT_HEIGHT*2), "GPU:%1.5f", totalDrawtime);
		print(12, 320-(DEBUG_FONT_HEIGHT*1), "ALL:%1.5f", totalUpdateTime + totalDrawtime);
		lastIntervalTime.start();

		GRAPH2D_CHECK_GL_ERROR();

		drawDebugMessage();

		PROFILE_DRAW();
#endif
	}

#if defined(DEBUG) || defined(_DEBUG) || defined(_DEBUG_) || !defined(NDEBUG)
	void Desktop::cleanDebugMessage()
	{
		DebugMessageInfomation* infomation = debugMessageInfomation;
		while(infomation)
		{
			DebugMessageInfomation* next = infomation->next;
			delete infomation;
			infomation = next;
		}
		debugMessageInfomation = NULL;
	}

	void Desktop::drawDebugMessage()
	{
		if(debugMessageFontTexture == NULL)
			return;

		debugMessageFontTexture->bind();

		const Vector2& textureSize = debugMessageFontTexture->getSize();

		for(DebugMessageInfomation* infomation = debugMessageInfomation; infomation; infomation = infomation->next)
		{
			const char* message = infomation->string.c_str();
			const int y = infomation->y;
			int x = infomation->x;

			while(*message)
			{
				GraphicDevice::begin(GraphicDevice::TYPE_TEXTURE_COORDINATE, GraphicDevice::TRIANGLES, Color::WHITE);

				const int index = *message;
				const float u = static_cast<float>(index % (DEBUG_FONT_TEXTURE_WIDTH / DEBUG_FONT_WIDTH)) * DEBUG_FONT_WIDTH;
				const float v = static_cast<float>(index / (DEBUG_FONT_TEXTURE_WIDTH / DEBUG_FONT_WIDTH)) * DEBUG_FONT_HEIGHT;

				const Vector2 t1 = Vector2(u, v) / textureSize;
				const Vector2 t2 = (Vector2(u, v) + Vector2(DEBUG_FONT_WIDTH, DEBUG_FONT_HEIGHT)) / textureSize;

				GraphicDevice::addTextureCoord(t1);
				GraphicDevice::addTextureCoord(Vector2(t2.x, t1.y));
				GraphicDevice::addTextureCoord(Vector2(t1.x, t2.y));
				GraphicDevice::addTextureCoord(Vector2(t2.x, t1.y));
				GraphicDevice::addTextureCoord(Vector2(t1.x, t2.y));
				GraphicDevice::addTextureCoord(t2);

				const Vector2 p1 = Vector2(static_cast<float>(x), static_cast<float>(y));
				const Vector2 p2 = p1 + Vector2(DEBUG_FONT_WIDTH, DEBUG_FONT_HEIGHT);

				GraphicDevice::addVertex(p1);
				GraphicDevice::addVertex(Vector2(p2.x, p1.y));
				GraphicDevice::addVertex(Vector2(p1.x, p2.y));
				GraphicDevice::addVertex(Vector2(p2.x, p1.y));
				GraphicDevice::addVertex(Vector2(p1.x, p2.y));
				GraphicDevice::addVertex(p2);

				GraphicDevice::end();

				x += DEBUG_FONT_WIDTH;
				message++;
			}
		}

		GraphicDevice::flush();

		cleanDebugMessage();
	}

	void Desktop::addDebugMessage(const int x, const int y, const std::string& message)
	{
		DebugMessageInfomation* infomation = new DebugMessageInfomation();
		if(infomation)
		{
			infomation->x = x;
			infomation->y = y;
			infomation->string = message;
			infomation->next = debugMessageInfomation;
			debugMessageInfomation = infomation;
		}
	}

#if defined(TARGET_WINDOWS)
#define vsnprintf   _vsnprintf
#endif

	void Desktop::print(const int x, const int y, const char* format, ...)
	{
		int size = 1024;
		std::vector<char> buffer(size);
		va_list args;

		va_start(args, format);
		int vssize = vsnprintf(&buffer[0], size, format, args);
		va_end(args);

		if(vssize >= 0 && vssize < size)
		{
			buffer.resize(vssize);
			addDebugMessage(x, y, std::string(buffer.begin(), buffer.end()));
		}
		else
		{
#if defined(TARGET_WINDOWS)
			va_start(args, format);
			vssize = _vscprintf(format, args);
			va_end(args);
#endif
			if(vssize > 0)
			{
				buffer.resize(vssize + 1);
				va_start(args, format);
				vssize = vsnprintf(&buffer[0], vssize + 1, format, args);
				va_end(args);
				if(vssize > 0)
				{
					buffer.resize(vssize);
					addDebugMessage(x, y, std::string(buffer.begin(), buffer.end()));
				}
			}
		}
	}

#if defined(TARGET_WINDOWS)
#undef vsnprintf
#endif

#endif
}
